package org.mapdb.store

import io.kotlintest.shouldBe
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.mapdb.TT
import org.mapdb.ser.Serializers
import org.mapdb.store.legacy.Store2
import org.mapdb.store.legacy.StoreDirect
import org.mapdb.store.legacy.Volume
import java.io.File
import java.util.*


class FileHeapBufStoreTest : StoreReopenTest() {
    override fun openStore(f:File) = FileHeapBufStore(f)
}

class FileHeapBufStoreRWLockTest : StoreReopenTest() {
    override fun openStore(f:File) = FileHeapBufStoreRWLock(f)
}

class LegacyStoreDirectTest : StoreReopenTest() {
    override fun openStore(f:File) = StoreDirect(Volume.fileFactory(f,1,false,0, Store2.VOLUME_CHUNK_SHIFT,1024))
}

abstract class StoreReopenTest(): StoreTest(){


    override fun openStore(): Store {
        val f = TT.tempFile()
        return openStore(f)
    }

    @Test fun reopen(){
        TT.withTempFile { f->
            var s = openStore(f)
            val recid = s.put("aa", Serializers.STRING)
            s.commit()
            s.close()

            s = openStore(f)
            s.get(recid,Serializers.STRING) shouldBe "aa"
            s.close()
        }
    }


    abstract fun openStore(file: File): Store
//
//    abstract val headerType:Long

// TODO file headers
//
//    @Test open fun headerType(){
//        val s = openStore(file)
//        s.put(11L, Serializers.LONG)
//        s.commit()
//        s.close()
//        val vol = RandomAccessFileVol.FACTORY.makeVolume(file.path, true)
//        assertEquals(CC.FILE_HEADER,vol.getUnsignedByte(0L).toLong())
//        assertEquals(headerType, vol.getUnsignedByte(1L).toLong())
//    }



    @Test fun put_reopen_get() {
        TT.withTempFile { file ->
            var e = openStore(file)
            val l = 11231203099090L
            val recid = e.put(l, Serializers.LONG)
            e.commit()
            e.close()
            e = openStore(file)

            assertEquals(l, e.get(recid, Serializers.LONG))
            e.close()
        }
    }


    @Test fun put_reopen_get_large() {
        TT.withTempFile { file ->
            var e = openStore(file)

            val b = TT.randomByteArray(1000000)
            val recid = e.put(b, Serializers.BYTE_ARRAY_NOSIZE)
            e.commit()
            e.close()
            e = openStore(file)

            assertTrue(Arrays.equals(b, e.get(recid, Serializers.BYTE_ARRAY_NOSIZE)))
            e.verify()
            e.close()
        }
    }

    @Test fun large_record_update2() {
        TT.withTempFile { file ->
            var e = openStore(file)
            val b = TT.randomByteArray(1000000)
            val recid = e.put(b, Serializers.BYTE_ARRAY_NOSIZE)
            e.update(recid, Serializers.BYTE_ARRAY_NOSIZE, b)
            var b2 = e.get(recid, Serializers.BYTE_ARRAY_NOSIZE)
            assertTrue(Arrays.equals(b, b2))
            e.commit()
            e.close()
            e = openStore(file)

            b2 = e.get(recid, Serializers.BYTE_ARRAY_NOSIZE)
            assertTrue(Arrays.equals(b, b2))
            e.verify()
            e.close()
        }
    }

    @Test fun large_record_larger() {
        if(TT.shortTest())
            return
        TT.withTempFile { file ->
            var e = openStore(file)
            val b = TT.randomByteArray(100000000)
            val recid = e.put(b, Serializers.BYTE_ARRAY_NOSIZE)
            var b2 = e.get(recid, Serializers.BYTE_ARRAY_NOSIZE)
            assertTrue(Arrays.equals(b, b2))
            e.verify()
            e.commit()
            e.close()
            e = openStore(file)

            b2 = e.get(recid, Serializers.BYTE_ARRAY_NOSIZE)
            assertTrue(Arrays.equals(b, b2))
            e.verify()
            e.close()
        }
    }



    @Test fun test_store_reopen() {
        TT.withTempFile { file ->
            var e = openStore(file)
            val recid = e.put("aaa", Serializers.STRING)
            e.commit()
            e.commit()
            e.close()
            e = openStore(file)
            val aaa = e.get(recid, Serializers.STRING)
            assertEquals("aaa", aaa)
            e.verify()
            e.close()
        }
    }

// TODO file locking
//    @Test fun file_lock(){
//        TT.withTempFile { file ->
//            var e = openStore(file)
//            val recid = e.put("aaa", Serializers.STRING)
//
//            assertFailsWith(DBException.FileLocked::class) {
//                openStore(file)
//            }
//
//            e.close()
//        }
//    }
// TODO missing test
//    @Test fun empty_rollback2(){
//        val e = openStore(file)
//        if(e is StoreTx)
//            e.rollback()
//        e.close()
//    }

    @Test fun empty_commit2(){
        TT.withTempFile { file ->
            val e = openStore(file)
            e.commit()
            e.close()
        }
    }



}